/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;
import java.util.ArrayList;

import nfse.gui.client.data.DiskSpace;

import org.acegisecurity.GrantedAuthorityImpl;

/*******************************************************************************
 * Convinience class and constant definitions for the NetFSE/Net/FSE codebase.
 * 
 * 
 * @author Ben Uphoff
 * 
 *         This code is the property of Los Alamos National Laboratory and the
 *         University of California, Copyright 2005
 */
public abstract class NetFSE {

	/***************************************************************************
	 * This switch is used to start various services in the NetFSEServer if the
	 * value is 'true'. This value is set during config file processing.
	 */
	public static boolean MASTER = false;

	/***************************************************************************
	 * The path to the nfcapd (NetFlow collector) binary
	 */
	public static String NETFLOW_NFCAPD = "/usr/local/bin/nfcapd";

	/***************************************************************************
	 * The path to the nfdump (NetFlow print) binary
	 */
	public static String NETFLOW_NFDUMP = "/usr/local/bin/nfdump";

	/***************************************************************************
	 * The path to the directory where nfcapd stores incoming NetFlow records
	 */
	public static String NETFLOW_BASE = "/var/log/netflow/";

	/***************************************************************************
	 * The home network IP/CIDR, used in Net/Sensor processing.
	 */
	public static String HOME_NETWORK = "";

	/***************************************************************************
	 * The home network IP/CIDR, used in Net/Sensor processing.
	 */
	public static int HOME_CIDR = 24;

	/***************************************************************************
	 * The home network IP/CIDR, used in Net/Sensor processing.
	 */
	private static long HOME_NETWORK_IP_VAL = -1;

	/***************************************************************************
	 * The frequency when the TempDBDelete process is run, in hours.
	 */
	public static int TEMP_DB_DELETE_HOURS = 168;

	public static int AUTO_STATS_DELETE_DAYS = 7;

	/***************************************************************************
	 * Switch for turning on IP address obfuscation, not currently in use.
	 */
	public static boolean OBFUSCATE = false;

	/***************************************************************************
	 * Name of the host, usually 'localhost'.
	 */
	public static String HOST_NAME = "localhost";

	/***************************************************************************
	 * Name of the domain, usually 'local'.
	 */
	public static String DOMAIN_NAME = "local";

	/***************************************************************************
	 * Default type used to specify the inclusion of all types in a query
	 */
	public static final int TYPE_ALL = 0;

	/***************************************************************************
	 * Maps type IDs (keys) to type names.
	 */
	private static HashMap TYPE_NAMES = null;

	/***************************************************************************
	 * Maps type IDs (keys) to type class names (fully qualified class names).
	 */
	public static HashMap TYPE_CLASS_NAMES = null;

	/***************************************************************************
	 * Maps type IDs (keys) to type instances (subclasses of nfse.NetFSERecord).
	 */
	public static HashMap TYPE_CLASSES = null;

	/***************************************************************************
	 * The number of records to select for each iteration during a migrate.
	 */
	public static int DUMP_RECORD_COUNT = 200000;

	/***************************************************************************
	 * The number of records to migrate. May be deprecated.
	 */
	public static int MIGRATE_COUNT = 4000000;

	/***************************************************************************
	 * Flag specifying whether or not to use SSL sockets for query operations
	 */
	public static boolean USE_SSL_QUERY = false;

	/***************************************************************************
	 * Flag specifying whether or not to use SSL sockets for sending results to
	 * a client
	 */
	public static boolean USE_SSL_RESULT = false;

	/***************************************************************************
	 * Flag specifying whether or not to use SSL sockets for receiving records
	 * from a data client
	 */
	public static boolean USE_SSL_DATA = false;

	/***************************************************************************
	 * A value used to set a socket's receive buffer
	 */
	public static final int SOCKET_RECV_SIZE = 65000;

	/***************************************************************************
	 * A value used to set a socket's send buffer
	 */
	public static final int SOCKET_SEND_SIZE = 65000;

	/***************************************************************************
	 * A value used to determine ho frequently Berkeley DB logs should be
	 * cleaned up
	 */
	public static final long LOG_CLEANUP_INTERVAL = 300000;

	/***************************************************************************
	 * The path to the location where the NetFSE log files will be stored
	 */
	public static String LOG_DIR = "";

	/***************************************************************************
	 * The maximum number of records to store in a database in nfse.DataSocket.
	 */
	public static int TEMP_TABLE_SIZE = 1000000;

	/***************************************************************************
	 * Identifier indicating a build task entry in the system metadata
	 */
	private static final int TASK_BUILD = 1;

	/***************************************************************************
	 * Identifier indicating a query task entry in the system metadata
	 */
	private static final int TASK_QUERY = 2;

	/***************************************************************************
	 * Flag value indicating that a query result has completed
	 */
	public static final int RESULT_SERVER_FLAG_DONE = 1;

	

	/***************************************************************************
	 * Default database name for the alerts database
	 */
	public static String ALERT_DB_DATABASE = "alerts";

	/***************************************************************************
	 * Default user name for the alert database
	 */
	public static String ALERT_DB_USER = "root";

	/***************************************************************************
	 * Default password for the alert database
	 */
	public static String ALERT_DB_PASSWORD = "NetFSEySQL";

	/***************************************************************************
	 * Default server for the alerts database
	 */
	public static String ALERT_DB_HOST = "localhost";

	/***************************************************************************
	 * The temp dir for misc functions
	 */
	public static String TEMP_DIR = "";

	/***************************************************************************
	 * Default user name for the system meta-database
	 */
	public static String METADATA_USER = "root";

	/***************************************************************************
	 * Default password for the system meta-database
	 */
	public static String METADATA_PASSWORD = "NetFSEySQL";

	/***************************************************************************
	 * Default server for the system meta-database
	 */
	public static String METADATA_HOST = "localhost";

	/***************************************************************************
	 * User for dynamic databases used by nfse.DataSocket
	 */
	public static String DYNAMIC_DB_USER = "root";

	/***************************************************************************
	 * Password for dynamic databases used by nfse.DataSocket
	 */
	public static String DYNAMIC_DB_PASSWORD = "NetFSEySQL";
	
	public static String PSQL = "psql";

	/***************************************************************************
	 * Host where search results should be stored (location of 'results'
	 * database). Typically 'localhost'.
	 */
	public static String RESULT_DB_HOST = "localhost";

	/***************************************************************************
	 * Database where search results should be stored. Typically 'results'.
	 */
	public static String RESULT_DB_DATABASE = "results";

	/***************************************************************************
	 * User for the 'results' database.
	 */
	public static String RESULT_DB_USER = "root";

	/***************************************************************************
	 * Password for the 'results' database.
	 */
	public static String RESULT_DB_PASSWORD = "NetFSEySQL";

	// public static int RESULT_DB_PORT = 3306;

	public static String STATS_DB_HOST = "localhost";

	public static String STATS_DB_DATABASE = "stats";

	public static String STATS_DB_USER = "root";

	public static String STATS_DB_PASSWORD = "NetFSEySQL";

	public static int STATS_DB_PORT = 3306;

	/***************************************************************************
	 * Default server for the system meta-database
	 */
	public static String METADATA_DATABASE = "metadata";

	public static String SYSLOG_SERVER = "127.0.0.1";

	public static int SYSLOG_PORT = 514;

	public static String EMAIL_SERVER = "";

	public static String EMAIL_NOTIFY = "";

	public static String EMAIL_SENDER = "";

	/***************************************************************************
	 * Location of the configuration file needed to run the NetFSE server
	 */
	public static String CONFIG_FILE = "/etc/nfse/local.cnf";

	/***************************************************************************
	 * Location of the server's Berkeley DB environment
	 */
	public static String DB_ENV_HOME = "";

	/***************************************************************************
	 * Size in bytes of the Berkeley DB environment's cache
	 */
	public static int DB_ENV_CACHE_SIZE = 500000000;

	/***************************************************************************
	 * Field identifier for destination IP addresses
	 */
	public static final int FIELD_DST_IP = 1;

	/***************************************************************************
	 * Field identifier for destination IP addresses
	 */
	public static final int FIELD_SRC_IP = 2;

	/***************************************************************************
	 * Field identifier for TCP port use by destination host (i.e. destination
	 * port)
	 */
	public static final int FIELD_DST_PORT = 3;

	/***************************************************************************
	 * Field identifier for start timestamp
	 */
	public static final int FIELD_START_TS = 4;

	/***************************************************************************
	 * Field identifier for end timestamp
	 */
	public static final int FIELD_END_TS = 5;

	/***************************************************************************
	 * Field identifier for TCP port use by source host (i.e. source port)
	 */
	public static final int FIELD_SRC_PORT = 6;

	/***************************************************************************
	 * Field identifier for bytes sent by the destination host (i.e. destination
	 * bytes)
	 */
	public static final int FIELD_DST_BYTES = 7;

	/***************************************************************************
	 * Field identifier for bytes sent by the source host (i.e. source bytes)
	 */
	public static final int FIELD_SRC_BYTES = 8;

	/***************************************************************************
	 * Field identifier for packets sent by the destination host (i.e.
	 * destination packets)
	 */
	public static final int FIELD_DST_PKTS = 9;

	/***************************************************************************
	 * Field identifier for packets sent by the source host (i.e. source
	 * packets)
	 */
	public static final int FIELD_SRC_PKTS = 10;

	/***************************************************************************
	 * Field identifier for record durations
	 */
	public static final int FIELD_DURATION = 11;

	/***************************************************************************
	 * Field identifier for IP protocol
	 */
	public static final int FIELD_PROTOCOL = 12;

	public static final int FIELD_BYTES = 13;

	public static final int FIELD_PACKETS = 14;

	/***************************************************************************
	 * Array of String objects mapping the names of fields to the field
	 * identifier (e.g. NetForSE.FIELD_NAMES[NetForSE.FIELD_SRC_PKTS] is the
	 * String "srcpkts")
	 */
	public static String[] FIELD_NAMES = { "", "dstip", "srcip", "dstport",
			"startts", "endts", "srcport", "dstbytes", "srcbytes", "dstpkts",
			"srcpkts", "duration", "protocol", "bytes", "pkts" };

	public static int[] FIELD_LENGTHS = { 0, 8, 8, 4, 8, 8, 4, 8, 8, 8, 8, 8,
			2, 8, 8 };

	/***************************************************************************
	 * The predicate identifier for equality (=)
	 */
	public static final int PREDICATE_EQUAL_TO = 1;

	/***************************************************************************
	 * The predicate identifier for <=
	 */
	public static final int PREDICATE_LESS_THAN_EQUAL_TO = 2;

	/***************************************************************************
	 * The predicate identifier for >=
	 */
	public static final int PREDICATE_GREATER_THAN_EQUAL_TO = 3;

	/***************************************************************************
	 * The predicate identifier for <
	 */
	public static final int PREDICATE_LESS_THAN = 4;

	/***************************************************************************
	 * The predicate identifier for >
	 */
	public static final int PREDICATE_GREATER_THAN = 5;

	/***************************************************************************
	 * The predicate identifier for range searches
	 */
	public static final int PREDICATE_RANGE = 6;

	/***************************************************************************
	 * Array of String objects mapping predicate symbols to predicate
	 * identifiers (e.g. NetForSE.PREDICATE_NAMES[NetForSE.PREDICATE_RANGE] is
	 * the String "~")
	 */
	public static String[] PREDICATES = { " ", "=", "<=", ">=", "<", ">", "~" };

	/***************************************************************************
	 * Array of String objects mapping month abbreviations to a month number
	 * 0-11 (e.g. NetForSE.MONTH_ABBRS[3] is the String "Apr")
	 */
	public static String[] MONTH_ABBRS = { "Jan", "Feb", "Mar", "Apr", "May",
			"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

	/***************************************************************************
	 * Upper case month abbreviations
	 */
	private static String[] MONTH_ABBRS_UC = { "JAN", "FEB", "MAR", "APR",
			"MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };

	private static long[] CIDR_MASKS = null;

	private static String[] CIDR_MASK_STRS = { "255.255.255.255",
			"255.255.255.254", "255.255.255.252", "255.255.255.248",
			"255.255.255.240", "255.255.255.224", "255.255.255.192",
			"255.255.255.128", "255.255.255.000", "255.255.254.000",
			"255.255.252.000", "255.255.248.000", "255.255.240.000",
			"255.255.224.000", "255.255.192.000", "255.255.128.000",
			"255.255.000.000", "255.254.000.000", "255.252.000.000",
			"255.248.000.000", "255.240.000.000", "255.224.000.000",
			"255.192.000.000", "255.128.000.000", "255.000.000.000",
			"254.000.000.000", "252.000.000.000", "248.000.000.000",
			"240.000.000.000", "224.000.000.000", "192.000.000.000",
			"128.000.000.000", "000.000.000.000" };

	public static long getCIDRMaskValue(int bits) {
		if (CIDR_MASKS == null) {
			CIDR_MASKS = new long[CIDR_MASK_STRS.length];
			for (int i = CIDR_MASK_STRS.length - 1; i >= 0; i--) {
				CIDR_MASKS[CIDR_MASKS.length - 1 - i] = NetFSEUtil
						.convertIPtoLong(CIDR_MASK_STRS[i]);
			}
		}
		return CIDR_MASKS[bits];
	}

	public static boolean isHomeNet(String ip) {

		long ipVal = NetFSEUtil.convertIPtoLong(ip);
		return isHomeNet(ipVal);
	}

	public static boolean isHomeNet(long ip) {
		return true;

		/*
		 * if (HOME_NETWORK_IP_VAL == -1) { HOME_NETWORK_IP_VAL =
		 * NetFSEUtil.convertIPtoLong(HOME_NETWORK); }
		 * 
		 * if ((ip & getCIDRMaskValue(HOME_CIDR)) == HOME_NETWORK_IP_VAL) return
		 * true; return false;
		 */
	}

	/***************************************************************************
	 * Default TCP port for the query server
	 */
	public static int QUERY_SERVER_PORT = 9096;

	/***************************************************************************
	 * Default host for the query server
	 */
	public static String QUERY_SERVER_HOST = "localhost";

	/***************************************************************************
	 * Default host for the data server
	 */
	public static String DATA_SERVER_HOST = "localhost";

	/***************************************************************************
	 * Default host for the stats server
	 */
	public static String STATS_SERVER_HOST = "localhost";

	/***************************************************************************
	 * Default host for the alert server
	 */
	public static String ALERT_SERVER_HOST = "localhost";

	/***************************************************************************
	 * Default TCP port for the data server
	 */
	public static int DATA_SERVER_PORT = 9097;

	/***************************************************************************
	 * Default TCP port for the result server
	 */
	public static int RESULT_SERVER_PORT = 9098;

	/***************************************************************************
	 * Default TCP port for the control server
	 */
	public static int CONTROL_SERVER_PORT = 9099;

	/***************************************************************************
	 * Default TCP port for the stats server
	 */
	public static int STATS_SERVER_PORT = 9095;

	/***************************************************************************
	 * Default TCP port for the stats server
	 */
	public static int ALERT_SERVER_PORT = 9093;

	/***************************************************************************
	 * Default TCP port for the Net/Sensor server
	 */
	public static int NET_SENSOR_SERVER_PORT = 9094;
	
	/***************************************************************************
	 * Default TCP port for the Net/Listener server
	 */
	public static int NET_LISTENER_SERVER_PORT = 9094;

	/***************************************************************************
	 * Local IP address for the interface running the Net/FSE server
	 */
	public static String LOCAL_IP_ADDRESS = null;

	/***************************************************************************
	 * Local host name for the interface running the Net/FSE server
	 */
	public static String LOCAL_HOST = null;

	/***************************************************************************
	 * Local node identifier for the interface running the Net/FSE server
	 */
	public static int NODE_ID = -1;

	/***************************************************************************
	 * Default host for the query server
	 */
	public static final String QUERY_HOST = "localhost";

	/***************************************************************************
	 * Default host for the Tomcat server
	 */
	public static String TOMCAT_HOST = NetFSEUtil.getHostName();

	/***************************************************************************
	 * Database connection to the system meta-database server
	 */
	public static Connection connection = null;

	/***************************************************************************
	 * Opens a connection to the main NetFSE meta-database.
	 * 
	 */
	public static synchronized void initializeConnection() {
		try {
			try {
				NetFSE.configure(CONFIG_FILE);
			} catch (Exception ioe) {
				ioe.printStackTrace();
			}

			Properties props = new Properties();
			props.setProperty("user", METADATA_USER);
			props.setProperty("password", METADATA_PASSWORD);
			props.setProperty("client_encoding", "UTF8");

			Class.forName("org.postgresql.Driver");
			String url = "jdbc:postgresql://" + NetFSE.METADATA_HOST + "/"
					+ NetFSE.METADATA_DATABASE;
			connection = DriverManager.getConnection(url, props);

		} catch (Exception E) {
			E.printStackTrace();
		}
	}

	/***************************************************************************
	 * Given a global field identifier, returns the field information from the
	 * system metadata.
	 * 
	 * @param globalFieldID
	 *            The field identifier for which to obtain field information
	 * @return A GlobalField object or null on error
	 */
	public static GlobalField getGlobalField(int globalFieldID) {
		return NetFSE.getGlobalField(NetFSE.FIELD_NAMES[globalFieldID]);
	}

	public static int getFieldLength(int id) {
		return FIELD_LENGTHS[id];
	}

	public static GlobalField getGlobalField(String globalFieldName) {
		try {
			GlobalField temp = new GlobalField();
			temp.setName(globalFieldName);
			temp.setId(NetFSE.getFieldType(globalFieldName));
			temp.setLength(NetFSE.getFieldLength(temp.getId()));
			return temp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/***************************************************************************
	 * Given a month abbreviation, returns the month number (1-12).
	 * 
	 * @param abbr
	 *            The three letter month abbreviation
	 * @return The number of the month (1-12)
	 */
	public static int getMonthValue(String abbr) {
		abbr = abbr.toUpperCase();
		int month = -1;
		for (int i = 0; i < MONTH_ABBRS_UC.length; i++) {
			if (abbr.equals(MONTH_ABBRS_UC[i])) {
				month = i + 1;
				break;
			}
		}
		return month;
	}

	/***************************************************************************
	 * Given a field identifier, returns the name of that field.
	 * 
	 * @param field
	 *            The field identifier from the system metadata
	 * @return The field name
	 */
	public static String getFieldName(int field) {
		if ((field <= 0) && (field > FIELD_NAMES.length))
			return "unknown";
		return FIELD_NAMES[field];
	}

	/***************************************************************************
	 * Given a field name, returns the identifier of that field.
	 * 
	 * @param field
	 *            The field name from the system metadata
	 * @return The identifier of the field from the system metadata
	 */
	public static int getFieldType(String field) {
		for (int i = 1; i < FIELD_NAMES.length; i++) {
			if (FIELD_NAMES[i].compareTo(field) == 0)
				return i;
		}
		return -1;
	}

	/***************************************************************************
	 * Given a predicate string, returns the identifier of that predicate.
	 * 
	 * @param predicate
	 *            The predicate string from the system metadata
	 * @return The identifier of the predicate from the system metadata
	 */
	public static int getPredicate(String predicate) {
		for (int i = 0; i < PREDICATES.length; i++)
			if (PREDICATES[i].compareTo(predicate) == 0)
				return i;
		return -1;
	}

	/***************************************************************************
	 * Given a predicate identifier, returns the name of that predicate.
	 * 
	 * @param predicate
	 *            The predicate identifier from the system metadata
	 * @return The string representation of the predicate
	 */
	public static String getPredicateName(int predicate) {
		if ((predicate <= 0) && (predicate > PREDICATES.length))
			return " ";
		return PREDICATES[predicate];
	}

	/***************************************************************************
	 * Returns a SensorInfo object the given ID.
	 * 
	 * @param sensorID
	 *            The sensor identifier for which to obtain information
	 * @return A SensorInfo object for or null on error
	 */
	public static SensorInfo getSensorInfo(int sensorID) {
		try {
			SensorInfo temp = null;

			Statement statement = NetFSE.createStatement();
			ResultSet rs = statement
					.executeQuery("select * from Sensors where ID = "
							+ sensorID);
			ResultSetMetaData meta = rs.getMetaData();
			if (rs.next())
				temp = new SensorInfo(rs.getInt(1), rs.getInt(2), rs
						.getString(3));
			rs.close();
			statement.close();

			// connection.close();
			return temp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static User getUser(String userName) {
		User temp = null;

		try {
			Statement s = createStatement();

			String sql = "select * from Users where user_name='" + userName
					+ "'";
			ResultSet rs = s.executeQuery(sql);
			if (rs.next()) {
				GrantedAuthorityImpl[] gas = new GrantedAuthorityImpl[2];
				gas[0] = new GrantedAuthorityImpl("USER_ROLE");
				gas[1] = new GrantedAuthorityImpl("ADMIN_ROLE");
				String password = rs.getString("Password");
				temp = new User(userName, password, true, true, true, true, gas);
			}
			rs.next();
			rs.close();
			s.close();
		} catch (Exception e) {
			e.printStackTrace();
			temp = null;
		}
		return temp;
	}

	private synchronized static Statement createStatement() throws Exception {
		if (connection == null)
			NetFSE.initializeConnection();

		Statement s = null;
		try {
			s = connection.createStatement();
		} catch (Exception e) {
			e.printStackTrace();
			NetFSE.initializeConnection();
			s = connection.createStatement();
		}
		return s;
	}

	/***************************************************************************
	 * Returns a SensorInfo array for all data types in the system metadata.
	 * 
	 * @return An array of SensorInfo objects or null on error
	 */
	public static SensorInfo[] getSensorInfo() {
		try {
			Vector temp = new Vector();
			Statement statement = NetFSE.createStatement();
			ResultSet rs = statement.executeQuery("select * from Sensors");
			ResultSetMetaData meta = rs.getMetaData();
			while (rs.next()) {
				SensorInfo ti = new SensorInfo(rs.getInt(1), rs.getInt(2), rs
						.getString(3));
				temp.addElement(ti);
			}
			rs.close();
			statement.close();
			// connection.close();
			SensorInfo[] info = new SensorInfo[temp.size()];
			for (int i = 0; i < info.length; i++)
				info[i] = (SensorInfo) temp.elementAt(i);
			return info;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/***************************************************************************
	 * Returns the user identifier given a user name.
	 * 
	 * @param user
	 *            The user name from the system metadata
	 * @return The user identifier from the system metadata
	 */
	public static int getUserID(String user) {
		int id = -1;
		try {
			Statement statement = NetFSE.createStatement();
			ResultSet rs = null;
			rs = statement.executeQuery("select * from Users where User_Name='"
					+ user + "'");
			if (rs.next())
				id = rs.getInt("ID");
			rs.close();
			statement.close();
			// connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return id;
	}

	/***************************************************************************
	 * Returns a ToolInfo object the given ID.
	 * 
	 * @param toolID
	 *            The tool identifier for which to obtain information
	 * @return A ToolInfo object for or null on error
	 */
	public static ToolInfo getToolInfo(int toolID) {
		try {
			Statement statement = NetFSE.createStatement();
			ResultSet rs = statement
					.executeQuery("select * from Tools where ID = " + toolID);
			ResultSetMetaData meta = rs.getMetaData();
			ToolInfo temp = null;
			if (rs.next())
				temp = new ToolInfo(rs.getInt(1), rs.getString(2), rs
						.getString(3));
			rs.close();
			statement.close();
			// connection.close();
			return temp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/***************************************************************************
	 * Returns a ToolInfo array for all data types in the system metadata.
	 * 
	 * @return An array of ToolInfo objects or null on error
	 */
	public static ToolInfo[] getToolInfo() {
		try {
			Vector temp = new Vector();
			Statement statement = NetFSE.createStatement();
			ResultSet rs = statement.executeQuery("select * from Tools");
			ResultSetMetaData meta = rs.getMetaData();
			while (rs.next()) {
				ToolInfo ti = new ToolInfo(rs.getInt(1), rs.getString(2), rs
						.getString(3));
				temp.addElement(ti);
			}
			rs.close();
			statement.close();

			// Build the array to return to caller
			ToolInfo[] info = new ToolInfo[temp.size()];
			for (int i = 0; i < info.length; i++)
				info[i] = (ToolInfo) temp.elementAt(i);
			return info;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/***************************************************************************
	 * Gets the status of all nodes in the system that have a query task. May be
	 * depreciated.
	 * 
	 * @return An array of NodeStatus objects or an empty (non-null) array on
	 *         error
	 */
	public static NodeStatus[] getQueryNodeStatus() {
		String sql = "select * from Nodes where Query != 0";
		return nodeStatus(sql);
	}

	/***************************************************************************
	 * Gets the status of all nodes in the system that have a build task. May be
	 * depreciated.
	 * 
	 * @return An array of NodeStatus objects or an empty (non-null) array on
	 *         error
	 */
	public static NodeStatus[] getBuildNodeStatus() {
		String sql = "select * from Nodes where Build != 0";
		return nodeStatus(sql);
	}

	/***************************************************************************
	 * Gets the status of all nodes in the system that have a task associated
	 * with the given sensor.
	 * 
	 * @param sensor
	 *            The sensor ID for which to obtain node status information
	 * @return An array of NodeStatus objects or an empty (non-null) array on
	 *         error
	 */
	public static NodeStatus[] getBuildNodeStatusBySensor(int sensor) {
		// Disabled the Node_Tasks feature for now, just return all build nodes
		return getBuildNodeStatus();

		// String sql = "select * from Nodes, Node_Tasks where Nodes.Build != 0
		// and Nodes.ID=Node_Tasks.Node_ID and Node_Tasks.Sensor_ID="
		// + sensor + " and Node_Tasks.Task_Type=" + NetFSE.TASK_BUILD;
		// return nodeStatus(sql);
	}

	/***************************************************************************
	 * Gets the status of all nodes in the system.
	 * 
	 * @return An array of NodeStatus objects indicating the state of nodes in
	 *         the system or an empty (non-null) array on error
	 */
	public static NodeStatus[] getNodeStatus() {
		String sql = "select * from Nodes";
		return nodeStatus(sql);
	}

	/***************************************************************************
	 * Gets the status of a particular node in the system by system ID.
	 * 
	 * @param nodeID
	 *            Unique system identfier of the node for which to obtain status
	 *            inofmration
	 * @return The status of node or a null if there was an error
	 */
	public static NodeStatus getNodeStatus(int nodeID) {
		String sql = "Select * from Nodes where ID = " + nodeID;
		NodeStatus[] status = nodeStatus(sql);
		if ((status == null) || (status.length == 0))
			return null;
		return status[0];
	}

	public static float getPostgresDiskFullPercent() throws Exception {
		String psqlDir = "/var/lib/pgsql/";
		return getDiskFullPercent(psqlDir);
	}
	
	public static float getDiskFullPercent(String path) throws Exception {
		if (!path.endsWith("/"))
			path += "/";
		float val = -1.0f;
		float rootVal = -1.0f;
		Process p = Runtime.getRuntime().exec("df");
		BufferedReader br = new BufferedReader(new InputStreamReader(p
				.getInputStream()));
		int lineCount = 0;
		String line = null;
		int maxLen = -1;
		while ((line = br.readLine()) != null) {

			String[] result = line.split("\\s+");
			// LineCount = 0 is the header. Skip header
			if ((result.length == 6) && lineCount != 0) {
				String dir = result[5] + "/";
				
				long spaceUsed = Long.parseLong(result[2]);
				long spaceAvailable = Long.parseLong(result[1]);
				float tempVal = (float)(((double)spaceUsed/(double)spaceAvailable)*100.0d);
				if (path.equals(dir)) {
					val = tempVal;
					break;
				} else if (path.startsWith(dir) && (maxLen == -1 || dir.length() > maxLen)) {
					val = tempVal;
					//System.out.println("VAL=" + val);
					maxLen = dir.length();
				} else if (dir.equals("//")) {
					rootVal = tempVal;
				}
			}
			lineCount++;

		}
		if (val == -1.0f) {
			val = rootVal;
		}

		return val;
	}

	/***************************************************************************
	 * Gets the status of a particular node in the system by name.
	 * 
	 * @param nodeName
	 *            Name of the node for which to obtain status inofmration
	 * @return The status of node or a null if there was an error
	 */
	public static NodeStatus getNodeStatus(String nodeName) {
		String sql = "Select * from Nodes where Name = '" + nodeName + "'";
		NodeStatus[] status = nodeStatus(sql);
		if ((status == null) || (status.length == 0))
			return null;
		return status[0];
	}

	/***************************************************************************
	 * Executes the SQL provided and returns the status of nodes in the system.
	 * 
	 * @param sql
	 *            The SQL generated by one of the above public getNodeStatus
	 *            methods
	 * @return An array of NodeStatus objects indicating the state of nodes in
	 *         the system or an empty (non-null) array on error
	 */
	private static NodeStatus[] nodeStatus(String sql) {
		/*
		 * if (true) { NodeStatus[] temp = new NodeStatus[1]; NodeStatus ns =
		 * new NodeStatus(); ns.id = NetFSE.NODE_ID; ns.name = NetFSE.HOST_NAME;
		 * ns.build = true; ns.query = true; }
		 */

		try {
			Vector temp = new Vector();

			Statement statement = NetFSE.createStatement();
			ResultSet rs = statement.executeQuery(sql);
			while (rs.next()) {
				NodeStatus ns = new NodeStatus();
				ns.setID(rs.getInt("ID"));
				ns.setName(rs.getString("Name"));
				ns.setBuild(rs.getBoolean("Build"));
				ns.setQuery(rs.getBoolean("Query"));
				ns.setDynamicPassword(rs.getString("Dynamic_DB_Password"));
				ns.setDynamicUser(rs.getString("Dynamic_DB_User"));
				temp.addElement(ns);
				// System.out.println("" + ns.id + ": " + ns.name);
			}
			rs.close();
			statement.close();

			// Build the array to return to the caller
			NodeStatus[] status = new NodeStatus[temp.size()];
			for (int i = 0; i < status.length; i++)
				status[i] = (NodeStatus) temp.elementAt(i);
			return status;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new NodeStatus[0];
	}

	public static synchronized void configure(String configFile)
			throws Exception {

		if (configFile != null) {

			Connection connection = null;
			Statement s = null;

			LineNumberReader in = new LineNumberReader(new FileReader(
					configFile));
			String line = in.readLine();
			// System.out.println(line);
			while (line != null) {
				// System.out.println(line);
				String[] tokens = line.split(" ");
				if (tokens[0].equals("Metadata::password")) {
					NetFSE.METADATA_PASSWORD = tokens[1].trim();
				} else if (tokens[0].equals("Metadata::user")) {
					NetFSE.METADATA_USER = tokens[1].trim();
				} else if (tokens[0].equals("Metadata::host")) {
					NetFSE.METADATA_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Metadata::database")) {
					NetFSE.METADATA_DATABASE = tokens[1].trim();
				} else if (tokens[0].equals("Dynamic::password")) {
					NetFSE.DYNAMIC_DB_PASSWORD = tokens[1].trim();
				} else if (tokens[0].equals("Dynamic::user")) {
					NetFSE.DYNAMIC_DB_USER = tokens[1].trim();
				} else if (tokens[0].equals("Result::password")) {
					NetFSE.RESULT_DB_PASSWORD = tokens[1].trim();
				} else if (tokens[0].equals("Result::user")) {
					NetFSE.RESULT_DB_USER = tokens[1].trim();
				} else if (tokens[0].equals("Result::host")) {
					NetFSE.RESULT_DB_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Result::database")) {
					NetFSE.RESULT_DB_DATABASE = tokens[1].trim();
				} else if (tokens[0].equals("Stats::password")) {
					NetFSE.STATS_DB_PASSWORD = tokens[1].trim();
				} else if (tokens[0].equals("Stats::user")) {
					NetFSE.STATS_DB_USER = tokens[1].trim();
				} else if (tokens[0].equals("Stats::host")) {
					NetFSE.STATS_DB_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Stats::database")) {
					NetFSE.STATS_DB_DATABASE = tokens[1].trim();
				} else if (tokens[0].equals("Alerts::password")) {
					NetFSE.ALERT_DB_PASSWORD = tokens[1].trim();
				} else if (tokens[0].equals("Alerts::user")) {
					NetFSE.ALERT_DB_USER = tokens[1].trim();
				} else if (tokens[0].equals("Alerts::host")) {
					NetFSE.ALERT_DB_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Alerts::database")) {
					NetFSE.ALERT_DB_DATABASE = tokens[1].trim();
				} else if (tokens[0].equals("Obfuscate")) {
					if (tokens[1].equals("true")) {
						NetFSE.OBFUSCATE = true;
					} else {
						NetFSE.OBFUSCATE = false;
					}
				} else if (tokens[0].equals("Master")) {
					if (tokens[1].equals("true")) {
						NetFSE.MASTER = true;
					} else {
						NetFSE.MASTER = false;
					}
				} else if (tokens[0].equals("PSQL")) {
				    NetFSE.PSQL = "";
                    for (int i = 1; i < tokens.length; i++)
                        NetFSE.PSQL += tokens[i] + " ";
                    NetFSE.PSQL = NetFSE.PSQL.trim();
                } else if (tokens[0].equals("HomeNetwork")) {
					String[] tokens2 = tokens[1].split("/");
					NetFSE.HOME_NETWORK = tokens2[0];
					NetFSE.HOME_CIDR = Integer.parseInt(tokens2[1]);
				} else if (tokens[0].equals("Log ")) {
					NetFSE.LOG_DIR = tokens[1].trim();
				} else if (tokens[0].equals("TempTableSize")) {
					try {
						NetFSE.TEMP_TABLE_SIZE = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("AutoStatsDeleteDays")) {
					try {
						NetFSE.AUTO_STATS_DELETE_DAYS = Integer
								.parseInt(tokens[1].trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("DbEnv::home")) {
					NetFSE.DB_ENV_HOME = tokens[1].trim();
				} else if (tokens[0].equals("DbEnv:cachesize")) {
					try {
						NetFSE.DB_ENV_CACHE_SIZE = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("Email::from")) {
					NetFSE.EMAIL_SENDER = tokens[1].trim();
				} else if (tokens[0].equals("Email::to")) {
					NetFSE.EMAIL_NOTIFY = tokens[1].trim();
				} else if (tokens[0].equals("Email::server")) {
					NetFSE.EMAIL_SERVER = tokens[1].trim();
				} else if (tokens[0].equals("Syslog::server")) {
					NetFSE.SYSLOG_SERVER = tokens[1].trim();
				} else if (tokens[0].equals("Syslog::port")) {
					NetFSE.SYSLOG_PORT = Integer.parseInt(tokens[1].trim());
				} else if (tokens[0].equals("Server::queryhost")) {
					NetFSE.QUERY_SERVER_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Server::datahost")) {
					NetFSE.DATA_SERVER_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Server::statshost")) {
					NetFSE.STATS_SERVER_HOST = tokens[1].trim();
				} else if (tokens[0].equals("Server::tempdir")) {
					NetFSE.TEMP_DIR = tokens[1].trim();
				} else if (tokens[0].equals("Server::listenerport")) {
					try {
						NetFSE.NET_LISTENER_SERVER_PORT = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("Server::queryport")) {
					try {
						NetFSE.QUERY_SERVER_PORT = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("Server::dataport")) {
					try {
						NetFSE.DATA_SERVER_PORT = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("Server::resultport")) {
					try {
						NetFSE.RESULT_SERVER_PORT = Integer.parseInt(tokens[1]
								.trim());
					} catch (Exception E) {
						E.printStackTrace();
					}
				} else if (tokens[0].equals("Migrate::count")) {
					NetFSE.MIGRATE_COUNT = Integer.parseInt(tokens[1].trim());
				} else if (tokens[0].equals("Migrate::dumpcount")) {
					NetFSE.DUMP_RECORD_COUNT = Integer.parseInt(tokens[1]
							.trim());
				} else if (tokens[0].equals("TempDBDelete::hours")) {
					NetFSE.TEMP_DB_DELETE_HOURS = Integer.parseInt(tokens[1]
							.trim());
				} else if (tokens[0].equals("NetFlow::nfdump")) {
					NetFSE.NETFLOW_NFDUMP = tokens[1];
				} else if (tokens[0].equals("NetFlow:nfcapd")) {
					NetFSE.NETFLOW_NFCAPD = tokens[1];
				} else if (tokens[0].equals("NetFlow::base")) {
					NetFSE.NETFLOW_BASE = tokens[1];
				} else if (tokens[0].equals("TempDBDelete::hours")) {
					NetFSE.TEMP_DB_DELETE_HOURS = Integer.parseInt(tokens[1]
							.trim());
				} else if (tokens[0].equals("Type::class") && NetFSE.MASTER) {
					String className = tokens[1];
					NetFSERecord rec = (NetFSERecord) Class.forName(className)
							.newInstance();
					int id = Integer.parseInt(tokens[2]);
					String name = tokens[3];
					rec.setTypeID(id);
					rec.setTypeName(name);

					// try {
					if (connection == null) {
						Properties props = new Properties();
						props.setProperty("user", METADATA_USER);
						props.setProperty("password", METADATA_PASSWORD);
						props.setProperty("client_encoding", "UTF8");

						Class.forName("org.postgresql.Driver");
						String url = "jdbc:postgresql://"
								+ NetFSE.METADATA_HOST + "/"
								+ NetFSE.METADATA_DATABASE;
						connection = DriverManager.getConnection(url, props);
						s = connection.createStatement();

						s.execute("delete from Type_Classes");
						s.execute("delete from Tools");
					}

					// s.execute("delete from Type_Classes where Type_ID=" +
					// id);
					s.execute("insert into Type_Classes values (" + id + ",'"
							+ className + "','" + name + "')");
					try {
						s.execute("create database " + className);
					} catch (Exception e) {

					}
					try {
						// s.execute("delete from Tools where ID=" + id);
						s.execute("insert into Tools values (" + id + ",'"
								+ name + "','')");
					} catch (Exception e) {

					}

					// } catch (Exception e) {
					// e.printStackTrace();
					// }

				} else if (tokens[0].equals("Node") && NetFSE.MASTER) {
					// Entries of the form: Node ID IP {build: 1 or 0} {query: 1
					// or 0} dynamic_db_user dynamic_db_password

					int id = Integer.parseInt(tokens[1]);
					String ip = tokens[2];
					int build = Integer.parseInt(tokens[3]);
					int query = Integer.parseInt(tokens[4]);
					String user = tokens[5];
					String password = tokens[6];

					s.execute("delete from Nodes where ID=" + id);
					s.execute("insert into Nodes values (" + id + ",'" + ip
							+ "'," + build + "," + query + ",'" + user + "','"
							+ password + "')");

				}
				line = in.readLine();
			}
			in.close();
			if (s != null) {
				s.close();
				connection.close();
			}
		}

		if (NetFSE.TYPE_CLASS_NAMES != null)
			return;

		NetFSE.TYPE_CLASS_NAMES = new HashMap();
		NetFSE.TYPE_CLASSES = new HashMap();
		NetFSE.TYPE_NAMES = new HashMap();
		NetFSE.TYPE_NAMES.put(new Integer(0), "All");

		try {
			Properties props = new Properties();
			props.setProperty("user", METADATA_USER);
			props.setProperty("password", METADATA_PASSWORD);
			props.setProperty("client_encoding", "UTF8");

			Class.forName("org.postgresql.Driver");
			String url = "jdbc:postgresql://" + NetFSE.METADATA_HOST + "/"
					+ NetFSE.METADATA_DATABASE;
			Connection connection = DriverManager.getConnection(url, props);
			Statement s = connection.createStatement();
			ResultSet rs = s.executeQuery("select * from Type_Classes");
			while (rs.next()) {
				String className = rs.getString("Class_Name");
				String typeName = rs.getString("Type_Name");
				int typeID = rs.getInt("Type_ID");
				NetFSERecord rec = (NetFSERecord) Class.forName(className)
						.newInstance();
				rec.setTypeID(typeID);
				rec.setTypeName(typeName);
				int id = rec.getTypeID();

				NetFSE.TYPE_NAMES.put(new Integer(id), typeName);
				NetFSE.TYPE_CLASS_NAMES.put(new Integer(id), className);
				NetFSE.TYPE_CLASSES.put(new Integer(id), rec);

			}
			rs.close();
			s.close();
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		try {
			FileInputStream propFile = new FileInputStream(
					"/home/ids/config/properties.txt");
			Properties p = new Properties(System.getProperties());
			p.load(propFile);

			// set the system properties
			System.setProperties(p);
			// display new properties

		} catch (Exception E) {
			System.setProperty("netforse.hostname", "localhost");
			// E.printStackTrace();
		}
		NetFSE.HOST_NAME = System.getProperty("netforse.hostname");

	}

	public static String getTypeName(int type) {
		if (NetFSE.TYPE_CLASSES == null) {
			try {
				NetFSE.configure(NetFSE.CONFIG_FILE);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String temp = (String) NetFSE.TYPE_NAMES.get(new Integer(type));
		return temp;
	}

	public static String getTypeClassName(int type) {
		if (NetFSE.TYPE_CLASSES == null) {
			try {
				NetFSE.configure(NetFSE.CONFIG_FILE);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String temp = (String) NetFSE.TYPE_CLASS_NAMES.get(new Integer(type));
		return temp;
	}

	public static NetFSERecord getTypeClass(int type) {
		if (NetFSE.TYPE_CLASSES == null) {
			try {
				NetFSE.configure(NetFSE.CONFIG_FILE);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return (NetFSERecord) NetFSE.TYPE_CLASSES.get(new Integer(type));
	}

	public static String getSchema(int type) {
		if (NetFSE.TYPE_CLASSES == null) {
			try {
				NetFSE.configure(NetFSE.CONFIG_FILE);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String temp = ((NetFSERecord) NetFSE.TYPE_CLASSES
				.get(new Integer(type))).getCreateFieldTableSQL(NetFSE
				.getTypeName(type));
		return temp;
	}

	public static String[] getTypeNames() {
		if (NetFSE.TYPE_CLASSES == null) {
			try {
				NetFSE.configure(NetFSE.CONFIG_FILE);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		Collection<String> values = NetFSE.TYPE_NAMES.values();
		int count = values.size() - 1;
		String[] temp = new String[count];
		Iterator it = values.iterator();
		int idx = 0;
		while (it.hasNext()) {
			String val = (String) it.next();
			if (!val.equals("All")) {
				temp[idx] = val;
				idx++;
			}
		}
		return temp;
	}

	public static int[] getTypes() {
		try {
			if (NetFSE.TYPE_CLASSES == null)
				NetFSE.configure(null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		Collection keys = NetFSE.TYPE_NAMES.keySet();
		int count = keys.size() - 1;
		int[] temp = new int[count];
		Iterator it = keys.iterator();
		int idx = 0;
		while (it.hasNext()) {
			int val = ((Integer) it.next()).intValue();
			if (val != 0) {
				temp[idx] = val;
				idx++;
			}
		}
		return temp;
	}

	public static boolean isTypeValid(int type) {
		if (type == 0)
			return true;
		if (NetFSE.TYPE_NAMES.get(new Integer(type)) != null)
			return true;
		return false;

	}

	/***************************************************************************
	 * Reads in the nodes file specified in the args.<br>
	 * Note: this may become obsolete in future releases.
	 * 
	 * @param config
	 *            The file to process
	 * @exception Exception
	 *                Any processing error will generate an exception
	 */
	public static void processNodeConfigFile(File config) throws Exception {

		boolean ok = true;
		Vector queryNodes = new Vector();
		Vector buildNodes = new Vector();
		LineNumberReader in = new LineNumberReader(new FileReader(config));
		String line = in.readLine();
		while (line != null) {
			ok = true;
			if (line.startsWith("IP ")) {
				NetFSE.LOCAL_IP_ADDRESS = line.substring(line.indexOf(' '))
						.trim();
			} else if (line.startsWith("ID ")) {
				NetFSE.NODE_ID = Integer.parseInt(line.substring(
						line.indexOf(' ')).trim());
			} else if (line.startsWith("HOST ")) {
				NetFSE.LOCAL_HOST = line.substring(line.indexOf(' ')).trim();
			} else if (line.startsWith("DOMAIN ")) {
				NetFSE.DOMAIN_NAME = line.substring(line.indexOf(' ')).trim();
			}
			line = in.readLine();
		}
		in.close();

	}

}